
pub mod exist_result;

use crate::config::run_setup::RUN_SETUP_CONFIG;
use crate::util::log_helper::{push_dev, push_error};
use chrono;
use exist_result::ExistResult;

pub trait PathHelper {
  fn to_str(&self) -> String;
}
impl PathHelper for std::path::PathBuf {
  fn to_str(&self) -> String {
    let os_str_path = self.as_os_str();
    let error_msg = format!("cannot translate os_str to str in path_helper: [{:?}]", os_str_path);
    let str_path = os_str_path.to_str().expect(error_msg.as_str());
    return String::from(str_path);
  }
}

pub fn get_execute_path_buf() -> std::path::PathBuf {
  std::env::current_exe().expect("cannot found current exe path")
}

pub fn get_execute_directory() -> std::path::PathBuf {
  let script_path = get_execute_path_buf();
  let target_path = script_path.parent().expect("cannot found directory of current exe");
  target_path.to_path_buf()
}

pub fn get_run_setup_path() -> String {
  let mut path_buf = get_execute_directory();
  path_buf.push("env-site-log.yml");
  path_buf.to_str()
}

pub fn get_log_file_path() -> String {
  let log_cache_path = &RUN_SETUP_CONFIG.log_cache;
  let mut path_buf = std::path::PathBuf::from(log_cache_path);
  let date_time = chrono::Local::now();
  let date_time_str = date_time.format("rust-log-%Y-%m-%d_%H-%M-%S.txt").to_string();
  path_buf.push(date_time_str);
  path_buf.to_str()
}

pub fn get_is_exists(file_path: &str) -> ExistResult {
  let result_is_exist = std::fs::exists(file_path);
  if result_is_exist.is_ok() {
    let is_exist = result_is_exist.unwrap();
    if is_exist {
      push_dev(format!("target file system entry already exist: [{}]", file_path));
      return ExistResult::Yes;
    }
    push_dev(format!("target file system entry is not exist: [{}]", file_path));
    return ExistResult::No;
  }
  push_error(format!("cannot check target file system entry  exist: [{}]", file_path));
  return ExistResult::CannotCheck;
}

pub fn create_dir_all(dir_path: &str) -> bool {
  let result = std::fs::create_dir_all(dir_path);
  if result.is_ok() {
    push_dev(format!("create directory success: [{}]", dir_path));
    return true;
  }
  push_error(format!("create directory failed: [{}]", dir_path));
  return false;
}

/**
 * @param file_extension --- without dot
 */
pub fn get_target_app_file_url(raw_str: &str, file_extension: &str) -> String {
  let raw_str_part = raw_str.split("/");
  let raw_str_last_part = raw_str_part.last().unwrap();
  let file_part = raw_str_last_part.split(".");
  let last_part = file_part.clone().last().unwrap();
  if last_part != file_extension {
    return String::new();
  }
  let mut clone_part = file_part.clone();
  let first_part = clone_part.nth(0).unwrap();
  if first_part.eq("app") {
    return String::from(raw_str_last_part);
  }
  return String::new();
}

/**
 * @param file_extension --- without dot
 */
pub fn get_target_app_file_url_from_vec(vec_string: &Vec<String>, file_extension: &str) -> String {
  for vec_one in vec_string {
    let target_one = get_target_app_file_url(vec_one.as_str(), file_extension);
    if !target_one.is_empty() {
      return target_one;
    }
  }
  return String::new();
}

pub fn get_target_app_file_url_by(
  target_dom: &mut tl::VDom, 
  html_str: &str,
  target_tag: &str,
  target_attr: &str
) -> Vec<String> {
  let mut target_vec: Vec<String> = Vec::new();
  let dom_parser = target_dom.parser();
  let selector_string = format!("{}[{}]", target_tag, target_attr);
  let iter_option = target_dom.query_selector(selector_string.as_str());
  if iter_option.is_none() {
    push_error(format!("cannot found {}[{}] in html: [{}]", target_tag, target_attr, html_str));
    return target_vec;
  }
  let elm_iter = iter_option.unwrap();
  for elm in elm_iter {
    let elm_str_option = elm.get(dom_parser);
    if elm_str_option.is_none() {
      continue;
    }
    let elm_node = elm_str_option.unwrap();
    let elm_tag_node_option = elm_node.as_tag();
    if elm_tag_node_option.is_none() {
      continue;
    }
    let elm_tag = elm_tag_node_option.unwrap();
    let elm_attr = elm_tag.attributes();
    let elm_attr_src_option_option = elm_attr.get(target_attr);
    if elm_attr_src_option_option.is_none() {
      continue;
    }
    let elm_attr_src_option = elm_attr_src_option_option.unwrap();
    if elm_attr_src_option.is_none() {
      continue;
    }
    let attr_src = elm_attr_src_option.unwrap();
    let src_str_option = attr_src.try_as_utf8_str();
    if src_str_option.is_none() {
      continue;
    }
    let src_str = src_str_option.unwrap();
    target_vec.push(String::from(src_str));
  }
  return target_vec;
}
